package repository;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;

public class Branch {
    /**
     * @param name 新建分支名称
     * @return 新建一分支指向当前分支下的commit
     */
    public static Branch create(String name) {
        Branch cur = Repository.getInstance().getCurrentBranch();
        byte[] commit = cur.commit;
        if (commit == null) {
            System.err.printf("fatal: Not a valid object name:%s%n", cur.name);
            System.exit(-1);
        }
        var b = new Branch(name, commit);
        b.write();
        return b;
    }

    /**
     * @param file head文件
     * @return 通过head文件返回其对应的分支
     */
    public static Branch load(File file) {
        String name = file.getName();
        if (!file.exists()) {
            return new Branch(name, null);
        }
        try (var in = new BufferedInputStream(new FileInputStream(file))) {
            byte[] commit = in.readNBytes(20);
            return new Branch(name, commit);
        } catch (FileNotFoundException e) {
            System.err.printf("Fatal: Branch %s do not valid%n", name);
            System.exit(-1);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * @param name 分支名称
     * @return 通过分支名称返回对应的分支
     */
    public static Branch findByName(String name) {
        return Branch.load(Repository.getInstance().getRefHeadsPath()
                .resolve(name).toFile());
    }

    /**
     * @return 获取默认主分支名称
     */
    public static String defaultMainBranch() {
        return "master";
    }

    /**
     * @param name 分支名称
     * @return 确认分支是否存在
     */
    public boolean exist(String name) {
        var file = new File(Repository.getInstance().getRefHeadsPath() + File.separator + name);
        return file.exists();
    }

    private final String name;
    private byte[] commit;

    /**
     * 构造方法
     *
     * @param name 分支名称
     * @param key  分支指向的commit的哈希值
     */
    public Branch(String name, byte[] key) {
        this.name = name;
        this.commit = key;
    }

    /**
     * @param commit 为分支指向的commit的赋哈希key值，并写入对应的head文件中
     */
    public void setCommit(byte[] commit) {
        this.commit = commit;
        write();
    }

    /**
     * @return 获取分支的名称
     */
    public String getName() {
        return name;
    }

    /**
     * @return 获取分支指向的commit的哈希值
     */
    public byte[] getCommit() {
        return commit;
    }

    /**
     * 向Branch类对象对应的仓库暂存区heads目录下文件中写入其指向的commit哈希值
     */
    public void write() {
        if (commit == null) {
            return;
        } // 没有提交时不保存
        try (var out = new BufferedOutputStream(new FileOutputStream(
                Repository.getInstance().getRefHeadsPath() + File.separator + name))
        ) {
            out.write(commit, 0, 20);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 在仓库暂存区heads目录下删除分支文件
     */
    public void delete() {
        try {
            Files.delete(Repository.getInstance().getRefHeadsPath().resolve(name));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param obj
     * @return 重写equals方法，比较分支名判断两Branch对象是否相同
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        return name.equals(((Branch) obj).name);
    }

    /**
     * @return 重写hashcode方法，返回分支名的hashcode值作为分支的hashcode
     */
    @Override
    public int hashCode() {
        return name.hashCode();
    }
}
